home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / DSPanic / PatchIt.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-23  |  5.7 KB  |  195 lines

  1. /*
  2.  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
  3.  *
  4.  * @APPLE_LICENSE_HEADER_START@
  5.  *
  6.  * The contents of this file constitute Original Code as defined in and
  7.  * are subject to the Apple Public Source License Version 1.1 (the
  8.  * "License").  You may not use this file except in compliance with the
  9.  * License.  Please obtain a copy of the License at
  10.  * http://www.apple.com/publicsource and read it before using this file.
  11.  *
  12.  * This Original Code and all software distributed under the License are
  13.  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14.  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17.  * License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * @APPLE_LICENSE_HEADER_END@
  21.  */
  22. /*
  23.  * MPEnabler - An example of patching funtions in the Mac OS X Kernel
  24.  *
  25.  * Yes, I know that I said you don't patch functions in kernel,
  26.  * but you should remember what your mother used to say,
  27.  *
  28.  *   "Do and I say, not as I do."
  29.  * 
  30.  * Josh de Cesare, MacHack 2000
  31.  */
  32.  
  33. #include "PatchIt.h"
  34.  
  35. extern void bcopy(void *from, void *to, long length);
  36. extern void bzero(void *addr, long length);
  37. extern void ml_phys_write(vm_offset_t paddr, unsigned int data);
  38.  
  39. PatchPtr gPatches;
  40.  
  41. static vm_offset_t gPatchPage;
  42. static vm_offset_t gPatchPagePhys;
  43. static long        *gPatchItStubAddr;
  44.  
  45. void InitPatchIt(void)
  46. {
  47.   // Get one page of wired memory.
  48.   kmem_alloc_wired(kernel_map, &gPatchPage, PAGE_SIZE);
  49.   
  50.   // Get the physical address of the page.
  51.   gPatchPagePhys = pmap_extract(kernel_pmap, gPatchPage);
  52.   
  53.   // Clear the memory to make sure all the valid's are zero.
  54.   bzero((void *)gPatchPage, PAGE_SIZE);
  55.   
  56.   gPatches = (PatchPtr)gPatchPage;
  57.   gPatchItStubAddr = (long *)PatchItStub;
  58. }
  59.  
  60.  
  61. void UnInitPatchIt(void)
  62. {
  63.   long cnt;
  64.   
  65.   for (cnt = 0; cnt < kMaxPatches; cnt++) {
  66.     UnPatchIt(gPatches + cnt);
  67.   }
  68.   
  69.   kmem_free(kernel_map, gPatchPage, PAGE_SIZE);
  70. }
  71.  
  72.  
  73. PatchPtr PatchIt(void *oldFunc, void *newFunc)
  74. {
  75.   long          cnt, physAddr, data;
  76.   unsigned long oldFuncAddr, patchFuncAddr, patchDataAddr;
  77.   PatchPtr      patch = 0;
  78.   
  79.   // Find a free slot.
  80.   for (cnt = 0; cnt < kMaxPatches; cnt++) {
  81.     if (!gPatches[cnt].valid) {
  82.       patch = gPatches + cnt;
  83.       break;
  84.     }
  85.   }
  86.   if (patch == 0) return 0;
  87.   
  88.   // Make the patch stub.
  89.   oldFuncAddr = (unsigned long)oldFunc + 0x18;
  90.   patch->patchStub[0] = gPatchItStubAddr[0] | (oldFuncAddr >> 16);
  91.   patch->patchStub[1] = gPatchItStubAddr[1] | (oldFuncAddr & 0xFFFC);
  92.   patch->patchStub[2] = gPatchItStubAddr[2];
  93.   bcopy(oldFunc, patch->patchStub + 3, 0x18);
  94.   patch->patchStub[9] = gPatchItStubAddr[5];
  95.   
  96.   // Flush the stub from data and instruction caches.
  97.   PatchItFlush(gPatchPage + (cnt * kPatchSize));
  98.   PatchItFlush(gPatchPage + (cnt * kPatchSize) + 0x20);
  99.   
  100.   // Get physical addresses for the old function.
  101.   oldFuncAddr = (unsigned long)oldFunc;
  102.   patch->targetPhys1 = pmap_extract(kernel_pmap, (vm_offset_t)oldFunc);
  103.   patch->targetPhys2 = pmap_extract(kernel_pmap, (vm_offset_t)oldFunc + 0x14);
  104.   
  105.   // Install the patch helper.
  106.   patchFuncAddr = (unsigned long)PatchItHelper;
  107.   patchDataAddr = (unsigned long)patch;
  108.   
  109.   physAddr = patch->targetPhys1;
  110.   data = gPatchItStubAddr[0] | (patchFuncAddr >> 16);
  111.   ml_phys_write(physAddr, data);
  112.   physAddr += 4;
  113.   
  114.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  115.   data = gPatchItStubAddr[1] | (patchFuncAddr & 0xFFFC);
  116.   ml_phys_write(physAddr, data);
  117.   physAddr += 4;
  118.   
  119.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  120.   data = gPatchItStubAddr[2];
  121.   ml_phys_write(physAddr, data);
  122.   physAddr += 4;
  123.   
  124.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  125.   data = gPatchItStubAddr[3] | (patchDataAddr >> 16);
  126.   ml_phys_write(physAddr, data);
  127.   physAddr += 4;
  128.   
  129.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  130.   data = gPatchItStubAddr[4] | (patchDataAddr & 0xFFFF);
  131.   ml_phys_write(physAddr, data);
  132.   physAddr += 4;
  133.   
  134.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  135.   data = gPatchItStubAddr[5];
  136.   ml_phys_write(physAddr, data);
  137.   physAddr += 4;
  138.   
  139.   // Flush the patch from data and instruction caches.
  140.   PatchItFlush((vm_offset_t)oldFunc);
  141.   PatchItFlush((vm_offset_t)oldFunc + 0x14);
  142.   
  143.   patch->oldFunc     = oldFunc;
  144.   patch->newFunc     = newFunc;
  145.   patch->valid       = 1;
  146.   
  147.   return patch;
  148. }
  149.  
  150. void UnPatchIt(PatchPtr patch)
  151. {
  152.   unsigned long oldFuncAddr, physAddr, data;
  153.   
  154.   if (!patch->valid) return;
  155.   patch->valid = 0;
  156.   
  157.   // Uninstall the patch.
  158.   physAddr = patch->targetPhys1;
  159.   data = patch->patchStub[3];
  160.   ml_phys_write(physAddr, data);
  161.   physAddr += 4;
  162.   
  163.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  164.   data = patch->patchStub[4];
  165.   ml_phys_write(physAddr, data);
  166.   physAddr += 4;
  167.   
  168.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  169.   data = patch->patchStub[5];
  170.   ml_phys_write(physAddr, data);
  171.   physAddr += 4;
  172.   
  173.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  174.   data = patch->patchStub[6];
  175.   ml_phys_write(physAddr, data);
  176.   physAddr += 4;
  177.   
  178.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  179.   data = patch->patchStub[7];
  180.   ml_phys_write(physAddr, data);
  181.   physAddr += 4;
  182.   
  183.   if ((physAddr & (PAGE_SIZE - 1)) == 0) physAddr = patch->targetPhys2;
  184.   data = patch->patchStub[8];
  185.   ml_phys_write(physAddr, data);
  186.   physAddr += 4;
  187.   
  188.   // Flush the original from data and instruction caches.
  189.   oldFuncAddr = (unsigned int)patch->oldFunc;
  190.   PatchItFlush(oldFuncAddr);
  191.   PatchItFlush(oldFuncAddr + 0x14);
  192.   
  193.   patch->valid   = 0;
  194. }
  195.